﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

/* Courtesy of CMPT 306 Tutorial notes */
namespace Pulse
{
    // We need a generic class for things like lists that will contain both Nodes and Leaves.  
    public abstract class Tree
    {
        // Both Nodes and Leaves have the option of being conditionally evaluated.  
        protected Func<bool> conditional;

        // Any Node will recurse; any Leaf will return its stored Action.  
        public abstract Action GetDecision();

        // Checking a condtional (a Func<bool>) is the same as invoking it and returning its result. 
        public bool CheckConditional()
        {
            return this.conditional.Invoke();
        }
    }

    // A DecisionLeaf encapusaltes an Action to perform.  
    public class DecisionLeaf : Tree
    {
        // The Action (void method with no parameters) to perform.  
        protected Action toDo;

        // Just a constructor.  
        public DecisionLeaf(Func<bool> conditional, Action toDo)
        {
            this.toDo = toDo;
            this.conditional = conditional;
        }

        // The decision of a DecisionLeaf is its stored Action, unlike for a DecisionNode.  
        public override Action GetDecision()
        {
            return this.toDo;
        }

    }

    public class DecisionNode : Tree
    {
        // A decision node contains a list of DecisionNodes/DecisionLeafs to conditionally perform.
        List<Tree> children;

        // Just initialize.
        public DecisionNode()
        {
            this.children = new List<Tree>();
        }

        // Add sequentially, in order of preference.  Once one child's condition returns true, 
        // it is the one that will be considered.  
        public void AddChild(Tree child)
        {
            this.children.Add(child);
        }

        // A DecisionNode has no decision by itself.  It will just recursively return the decision
        // of the first child whose condition is true.  
        public override Action GetDecision()
        {
            Tree toRecurseDown = new DecisionNode();
            bool found = false;

            foreach (Tree child in this.children)
            {
                if (!found)
                {
                    if (child.CheckConditional())
                    {
                        found = true;
                        toRecurseDown = child;
                    }
                }
            }

            return toRecurseDown.GetDecision();

        }

        // When a DecisionNode has a list of possible decisions, we'll want to perform the last one regardless. 
        // So when someone is building a tree, they need access to a Func<bool> that will always return true.
        public static Func<bool> GetDefault()
        {
            return new Func<bool>(() => true);
        }

    }
}
